﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Cms.Application.Admin.Views;
using Cms.Application.IO;
using Cms.Data;
using Cms.Domain;
using Cms.Domain.Comparers;
using Cms.Domain.RepositoryInterfaces;
using Cms.Utilities;
using iLib.Web.UI;

namespace Cms.Application.Admin.Presenters
{
    public class EditMasterTemplatePresenter : BasePresenter
    {
        private readonly Administrator _administrator;
        private readonly IEditMasterTemplateView _view;

        public IDiskAccess DiskAccess { get; set; }

        public EditMasterTemplatePresenter(IEditMasterTemplateView view)
            : this(view, new RepositoryFactory())
        {
            DiskAccess = new DiskAccess();
        }
        
        public EditMasterTemplatePresenter(IEditMasterTemplateView view, IRepositoryFactory repositoryFactory)
            : base(view, repositoryFactory)
        {
            _view = view;
            _administrator = AdministratorRepository.GetAdministrator(_view.AdministratorID);
            if (!_administrator.HasPermission.EditMasterTemplate)
                _view.RedirectToPermissionDeniedPage();
        }
        
        public void SetLocales()
        {
            _view.SetLocales(_administrator.CurrentSite.Locales);
        }
        
        public void Initialize()
        {
            if (_administrator.CurrentSiteLocale != null)
            {
                _view.SelectedLocaleID = _administrator.CurrentSiteLocale.ID;
            }
            SetVersions();
            if (!_administrator.HasPermission.PublishContent)
            {
                // This check must be done after SetVersions, since that method also affects the possibility to publish
                _view.PublishContentNotAllowed();
            }
            if (_view.MasterTemplateID == -1)
            {
                _view.SourceCode = DiskAccess.ReadTextFile("Admin\\Resources\\NewMasterTemplate.Master");
            }
            else
            {
                MasterTemplate masterTemplate = SiteRepository.GetMasterTemplate(_view.MasterTemplateID);
                _view.Name = masterTemplate.Name;
                _view.SourceCode = masterTemplate.GetCode();
                _view.SetStylesheets(masterTemplate.GetStylesheets(), masterTemplate.GetUnusedStylesheets());
            }
        }
        
        public void SetVersions()
        {
            if (_view.MasterTemplateID > 0)
            {
                MasterTemplate masterTemplate = SiteRepository.GetMasterTemplate(_view.MasterTemplateID);
                IList<ContentTranslationVersion> versions = masterTemplate.GetContentVersions(_view.SelectedLocaleID);
                int publishedVersionID = -1;
                if (masterTemplate.ContentSets.ContainsKey(_view.SelectedLocaleID) && masterTemplate.ContentSets[_view.SelectedLocaleID].PublishedVersion != null)
                {
                    publishedVersionID = masterTemplate.ContentSets[_view.SelectedLocaleID].PublishedVersion.ID;
                }
                _view.SetVersions(versions, publishedVersionID);
                List<ScheduledPublishing> scheduledPublishings = versions.SelectMany(ctv => ctv.ScheduledPublishings).ToList();
                scheduledPublishings.Sort(new ScheduledPublishingComparer(SortDirection.Ascending));
                _view.SetScheduledPublishings(scheduledPublishings);
            }
            else
            {
                _view.SetVersions(new List<ContentTranslationVersion>(), -1);
                _view.SetScheduledPublishings(new List<ScheduledPublishing>());
            }
        }

        public void Save()
        {
            if (_view.CurrentTab == "properties")
            {
                ValidateProperties();
            }
            if (!IsValid)
            {
                return;
            }
            MasterTemplate masterTemplate;
            if (_view.MasterTemplateID == -1)
            {
                masterTemplate = new MasterTemplate { Site = _administrator.CurrentSite };
                masterTemplate.Site.MasterTemplates.Add(masterTemplate);
                if (_administrator.CurrentSite.DefaultMasterTemplate == null)
                {
                    _administrator.CurrentSite.DefaultMasterTemplate = masterTemplate;
                }
            }
            else
            {
                masterTemplate = SiteRepository.GetMasterTemplate(_view.MasterTemplateID);

                // TODO: Check current Areas and compare them to _view.Areas
            }
            masterTemplate.Name = _view.Name;
            masterTemplate.SetCode(_view.SourceCode, _administrator);
            string[] areas = _view.MasterTemplateAreas.Split(",".ToCharArray());
            masterTemplate.Areas.Clear();
            foreach (string area in areas.Where(area => area.Trim() != string.Empty))
            {
                masterTemplate.Areas.Add(area);
            }
            string[] pageAreas = _view.PageAreas.Split(",".ToCharArray());
            masterTemplate.PageAreas.Clear();
            foreach (string area in pageAreas.Where(area => area.Trim() != string.Empty))
            {
                masterTemplate.PageAreas.Add(area);
            }
            SiteRepository.SaveSite(_administrator.CurrentSite);
            DiskAccess.DeleteFile("__System\\MasterTemplates\\" + masterTemplate.ID + ".master");
            DiskAccess.CreateTextFile("__System\\MasterTemplates\\" + masterTemplate.ID + ".master", _view.SourceCode);
            _view.SetMasterTemplateID(masterTemplate.ID);
        }
        
        public void SaveSelectedLocale()
        {
            _administrator.CurrentSiteLocale = LocaleRepository.GetLocale(_view.SelectedLocaleID);
            AdministratorRepository.SaveAdministrator(_administrator);
        }
        
        public void Publish()
        {
            MasterTemplate mt = SiteRepository.GetMasterTemplate(_view.MasterTemplateID);
            ContentTranslationVersion ctv = ContentRepository.GetContentTranslationVersion(_view.SelectedVersionID);
            if (ctv == null)
            {
                return;
            }
            ctv.Publish();
            SiteRepository.SaveSite(_administrator.CurrentSite);
            SetVersions();
            _view.SelectedVersionID = ctv.ID;
        }
        
        public void Move(string draggedID, string dropzoneID, string dropzonePart)
        {
            Stylesheet stylesheet = SiteRepository.GetStylesheet(int.Parse(draggedID.Substring(1)));
            MasterTemplate masterTemplate = SiteRepository.GetMasterTemplate(_view.MasterTemplateID);

            // Remove an already selected stylesheet
            if (draggedID.Substring(0, 1) == "S" && dropzoneID == "availableDropzone")
            {
                masterTemplate.RemoveStylesheet(stylesheet);
            }
            else if (draggedID.Substring(0, 1) == "A" && dropzoneID == "ctl00_body_pnlNoSelectedStylesheets")
            {
                // Add the first stylesheet
                masterTemplate.AddStylesheet(stylesheet);
            }
            else if (dropzoneID.Substring(0, 1) == "T" && draggedID.Substring(1) != dropzoneID.Substring(1))
            {
                // Add another stylesheet or re-order already selected stylesheets
                if (draggedID.Substring(0, 1) == "S")
                {
                    masterTemplate.RemoveStylesheet(stylesheet);
                    SiteRepository.SaveSite(masterTemplate.Site);
                }
                for (int i = 0; i < masterTemplate.AssociatedStylesheets.Count; i++)
                {
                    if (masterTemplate.AssociatedStylesheets[i].Stylesheet.ID == int.Parse(dropzoneID.Substring(1)))
                    {
                        if (dropzonePart == "upper")
                        {
                            masterTemplate.InsertStylesheet(i, stylesheet);
                        }
                        else
                        {
                            if (i < masterTemplate.AssociatedStylesheets.Count - 1)
                            {
                                masterTemplate.InsertStylesheet(i + 1, stylesheet);
                            }
                            else
                            {
                                masterTemplate.AddStylesheet(stylesheet);
                            }
                        }
                        break;
                    }
                }
            }
            SiteRepository.SaveSite(masterTemplate.Site);
            _view.SetStylesheets(masterTemplate.GetStylesheets(), masterTemplate.GetUnusedStylesheets());
        }
        
        public IList<ContentSetContainer> GetContentContainers(string areaID, string contentType)
        {
            ContentSetContainer container = SiteRepository.GetMasterTemplate(_view.MasterTemplateID);
            IList<ContentSetContainer> containers = new List<ContentSetContainer>();
            if (container == null)
                return containers;
            Content c = container.GetContent(areaID);
            foreach (PageContentLink pl in c.Pages)
                containers.Add(pl.Page);
            foreach (MasterTemplateContentLink mtl in c.MasterTemplates)
                if (mtl.MasterTemplate.ID != _view.MasterTemplateID)
                    containers.Add(mtl.MasterTemplate);
            foreach (DetailTemplateContentLink dtl in c.DetailTemplates)
                containers.Add(dtl.DetailTemplate);
            return containers;
        }

        public void BreakContentLink(string areaID, string contentType)
        {
            MasterTemplate container = SiteRepository.GetMasterTemplate(_view.MasterTemplateID);
            if (container == null)
                return;
            Content content = container.GetContent(areaID);
            content.RemoveMasterTemplate(container);
            foreach (var translation in content.Translations)
            {
                ContentSet set = container.GetContentSet(LocaleRepository.GetLocale(translation.Key));
                foreach (ContentTranslationVersion ctv in translation.Value.Versions)
                {
                    set.TranslationVersions.Remove(ctv);
                }
            }
            SiteRepository.SaveSite(_administrator.CurrentSite);
            SetVersions();
        }
        
        public void SchedulePublishing(int contentTranslationVersionID, DateTime scheduledPublishingDateTime)
        {
            ContentTranslationVersion ctv = ContentRepository.GetContentTranslationVersion(contentTranslationVersionID);
            if (ctv == null)
                return;
            var scheduledPublishing = new ScheduledPublishing
                                          {
                                              Timestamp = scheduledPublishingDateTime.Ticks.ToString(),
                                              ContentTranslationVersion = ctv,
                                              Description = null
                                          };
            ctv.ScheduledPublishings.Add(scheduledPublishing);
            SiteRepository.SaveSite(_administrator.CurrentSite);
            SetVersions();
        }

        public void DeleteScheduledPublishing(int id)
        {
            ContentRepository.DeleteScheduledPublishing(id);
            SetVersions();
        }

        private void ValidateProperties()
        {
            if (_view.Name.Trim() == string.Empty)
            {
                AddValidationError(GetText(_view, "NoNameError"));
            }
            if (!_administrator.CurrentSite.CanMasterTemplateBeNamedTo(_view.MasterTemplateID, _view.Name))
            {
                AddValidationError(GetText(_view, "NameCollisionError"));
            }
            string sourceCodeValidationResult = _view.GetSourceCodeStatus();
            if (sourceCodeValidationResult != "ok")
            {
                string errorText = GetText(_view, "SourceCodeError");
                errorText = errorText.Replace("[[ErrorMessage]]", sourceCodeValidationResult);
                string encryptedCredentials = Cipher.Encrypt(_administrator.Username + (char)9 + _administrator.Password);
                string url = Url.FullPath + "Admin/Default.aspx?credentials=" +
                             HttpUtility.UrlEncode(encryptedCredentials) + "&ReturnUrl=" +
                             HttpUtility.UrlEncode(_view.UserTempDirectory + "ErrorDetails.aspx?v=" + DateTime.Now.Ticks);
                errorText = errorText.Replace("[[ErrorDetailsUrl]]", url);
                AddValidationError(errorText);
            }
        }
    }
}